package com.travel.service.Impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.travel.common.utils.JwtUtil;
import com.travel.mapper.UserMapper;
import com.travel.pojo.dto.PageDTO;
import com.travel.pojo.dto.UserDTO;
import com.travel.pojo.dto.UserQueryDTO;
import com.travel.pojo.entity.User;
import com.travel.pojo.vo.*;
import com.travel.service.IUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    private final UserMapper userMapper;

    @Override
    public PageDTO<UserVO> pageListUser(UserQueryDTO userQueryDTO) {
        String name = userQueryDTO.getUsername();
        String phone = userQueryDTO.getPhone();
        Integer gender = userQueryDTO.getGender();
        String ipLocation = userQueryDTO.getIpLocation();
        BigDecimal maxAge = userQueryDTO.getMaxAge();
        BigDecimal minAge = userQueryDTO.getMinAge();
        String userPermission = userQueryDTO.getUserPermission();

        Page<User> page = Page.of(userQueryDTO.getPage(), userQueryDTO.getPageSize());
        Page<User> pageUser = lambdaQuery()
                .like(name != null, User::getUsername, name)
                .eq(phone != null, User::getPhone, phone)
                .eq(gender != null, User::getGender, gender)
                .eq(ipLocation != null, User::getIpLocation, ipLocation)
                .eq(userPermission != null, User::getUserPermission, userPermission)
                .le(maxAge != null, User::getAge, maxAge)
                .gt(minAge != null, User::getAge, minAge).page(page);

        PageDTO<UserVO> userPageDTO = new PageDTO<>();
        List<UserVO> collect = pageUser.getRecords().stream().map(user -> {
            return BeanUtil.toBean(user, UserVO.class);
        }).collect(Collectors.toList());
        userPageDTO.setList(collect);
        userPageDTO.setTotal((int) pageUser.getTotal());
        userPageDTO.setPages((int) pageUser.getPages());
        return userPageDTO;
    }

    @Override
    public void addUser(UserDTO userDTO) {
        User user = BeanUtil.copyProperties(userDTO, User.class);
        user.setRegisterTime(LocalDateTime.now());
        userMapper.insert(user);
    }

    @Override
    public void updateUser(Long id, UserDTO userDTO) {
        LambdaUpdateWrapper<User> wrapper = Wrappers.lambdaUpdate();
        wrapper.eq(User::getId, id)
                .set(userDTO.getAge() != null, User::getAge, userDTO.getAge())
                .set(userDTO.getGender() != null, User::getGender, userDTO.getGender())
                .set(userDTO.getUsername() != null, User::getUsername, userDTO.getUsername())
                .set(userDTO.getPhone() != null, User::getPhone, userDTO.getPhone())
                .set(userDTO.getPassword() != null, User::getPassword, userDTO.getPassword())
                .set(userDTO.getIpLocation() != null, User::getIpLocation, userDTO.getIpLocation())
                .set(userDTO.getUserPermission() != null, User::getUserPermission, userDTO.getUserPermission());
        userMapper.update(null, wrapper);
    }

    @Override
    public UserStatsVO getStats() {
        Integer totalUsers = Math.toIntExact(userMapper.selectCount(null));
        Integer todayNewUsers = getTodayNewUsers();
        Integer activeUsers = getActiveUsers(7);
        Integer vipUsers = getVipUsers();
        List<IpGrowth> ipGrowth = getIpGrowth(7);
        List<IpDistribution> ipDistribution = getIpDistribution();
        List<AgeDistribution> ageDistribution = getAgeDistribution();
        return UserStatsVO.builder()
                .todayNewUsers(todayNewUsers)
                .activeUsers(activeUsers)
                .ipDistribution(ipDistribution)
                .ageDistribution(ageDistribution)
                .totalUsers(totalUsers)
                .vipUsers(vipUsers)
                .ipGrowth(ipGrowth)
                .build();

    }

    @Override
    public User login(UserDTO userDTO) {
        return lambdaQuery().eq(User::getUsername, userDTO.getUsername())
                .eq(User::getPhone, userDTO.getPhone())
                .eq(User::getPassword, userDTO.getPassword()).one();
    }

    private List<IpGrowth> getIpGrowth(int days) {
        // 1. 计算起始日期
        LocalDateTime startDate = LocalDateTime.now().minusDays(days);

        // 2. 查询最近days天内各IP属地的新增用户数
        List<Map<String, Object>> results = userMapper.selectMaps(new QueryWrapper<User>()
                .select("ip_location AS region", "COUNT(*) AS value")
                .ge("register_time", startDate)  // 注册时间在指定天数内
                .isNotNull("ip_location")        // IP属地不为空
                .groupBy("ip_location")
                .orderByDesc("value")
                .last("LIMIT 10")                // 取前10个地区
        );

        // 3. 转换为VO对象
        return results.stream()
                .map(record -> new IpGrowth(
                        (String) record.get("region"),
                        ((Long) record.get("value")).intValue()
                ))
                .collect(Collectors.toList());
    }

    private int getTodayNewUsers() {
        LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
        return Math.toIntExact(userMapper.selectCount(new LambdaQueryWrapper<User>()
                .ge(User::getRegisterTime, startOfDay)));
    }

    private Integer getActiveUsers(int days) {
        LocalDateTime startDate = LocalDateTime.now().minusDays(days);
        return Math.toIntExact(userMapper.selectCount(new LambdaQueryWrapper<User>()
                .ge(User::getRegisterTime, startDate)));
    }

    private Integer getVipUsers() {
        return Math.toIntExact(userMapper.selectCount(new LambdaQueryWrapper<User>()
                .in(User::getUserPermission,
                        Arrays.asList(User.UserPermission.普通用户, User.UserPermission.SVIP用户))));
    }


    private List<IpDistribution> getIpDistribution() {
        return userMapper.selectIpDistribution();
    }

    private List<AgeDistribution> getAgeDistribution() {
        // 预定义所有年龄段
        Map<String, AgeDistribution> ageMap = new LinkedHashMap<>();
        ageMap.put("18岁以下", new AgeDistribution("18岁以下", 0, "#FF9F7F"));
        ageMap.put("18-25岁", new AgeDistribution("18-25岁", 0, "#FFD700"));
        ageMap.put("26-35岁", new AgeDistribution("26-35岁", 0, "#36A2EB"));
        ageMap.put("36-45岁", new AgeDistribution("36-45岁", 0, "#4BC0C0"));
        ageMap.put("46岁以上", new AgeDistribution("46岁以上", 0, "#9966FF"));

        // 1. 查询各年龄段用户数量
        List<Map<String, Object>> ageGroups = userMapper.selectMaps(new QueryWrapper<User>()
                .select(
                        "CASE " +
                                "  WHEN age < 18 THEN '18岁以下' " +
                                "  WHEN age BETWEEN 18 AND 25 THEN '18-25岁' " +
                                "  WHEN age BETWEEN 26 AND 35 THEN '26-35岁' " +
                                "  WHEN age BETWEEN 36 AND 45 THEN '36-45岁' " +
                                "  ELSE '46岁以上' " +
                                "END AS ageGroup",
                        "COUNT(*) AS value"
                )
                .isNotNull("age")
                .groupBy("ageGroup")
        );

        // 2. 填充实际数据
        ageGroups.forEach(record -> {
            String age = (String) record.get("ageGroup");
            int value = ((Number) record.get("value")).intValue();
            if (ageMap.containsKey(age)) {
                ageMap.get(age).setValue(value);
            }
        });

        // 3. 按value降序排序并返回
        return ageMap.values().stream()
                .sorted((a, b) -> b.getValue() - a.getValue())
                .collect(Collectors.toList());
    }

}
